from flask import Blueprint, request, jsonify, current_app
from flask_login import current_user, login_user, logout_user, login_required # type: ignore
from api.models import User, VerificationCode
from api import db  # 从 api 包导入 db 实例
from api.errors import bad_request, unauthorized
import random
from datetime import datetime, timedelta
import re
from functools import wraps

auth_bp = Blueprint('auth', __name__)

def is_valid_phone(phone):
    """验证手机号格式"""
    pattern = re.compile(r'^1[3-9]\d{9}$')
    return bool(pattern.match(phone))

@auth_bp.route('/api/auth/send-code', methods=['POST'])
def send_verification_code():
    try:
        data = request.get_json()
        if not data:
            return bad_request('无效的请求数据')
            
        phone = data.get('phone', '').strip()
        if not phone:
            return bad_request('手机号不能为空')
        
        # 验证手机号格式
        if not is_valid_phone(phone):
            return bad_request('无效的手机号格式')
        
        # 检查发送频率（同一手机号60秒内不能重复发送）
        last_code = VerificationCode.query.filter_by(
            phone=phone,
            is_used=False
        ).order_by(VerificationCode.id.desc()).first()
        
        current_time = datetime.utcnow()
        if last_code:
            # 获取最后一次发送验证码的记录数
            send_count = VerificationCode.query.filter(
                VerificationCode.phone == phone,
                VerificationCode.id > (last_code.id - 10)  # 检查最近10条记录
            ).count()
            
            # 如果1小时内发送超过5次，限制发送
            if send_count >= 5:
                return bad_request('发送次数过多，请稍后再试')
        
        # 生成6位随机验证码
        code = ''.join(random.choices('0123456789', k=6))
        
        # 将该手机号的旧验证码标记为已使用
        VerificationCode.query.filter_by(phone=phone, is_used=False).update({'is_used': True})
        
        # 创建新验证码记录
        verification_code = VerificationCode(
            phone=phone,
            code=code,
            is_used=False
        )
        
        db.session.add(verification_code)
        db.session.commit()
        
        # TODO: 这里应该添加发送短信的逻辑
        # 为了测试，这里先打印验证码
        current_app.logger.info(f'验证码: {code} 已发送到手机: {phone}')
        
        return jsonify({
            'code': 200,
            'message': '验证码已发送',
            'data': {
                'phone': phone[-4:],  # 只返回手机号后4位
                'expire_time': '有效期5分钟',   # 验证码有效期5分钟
                'code': code
            }
        })
        
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(f'发送验证码失败: {str(e)}')
        return bad_request('发送验证码失败，请稍后重试')

# 添加一个验证验证码的工具函数
def verify_code(phone, code):
    """
    验证验证码是否有效
    """
    if not phone or not code:
        return False
        
    # 查找最新的未使用的验证码
    verification = VerificationCode.query.filter_by(
        phone=phone,
        code=code,
        is_used=False
    ).order_by(VerificationCode.id.desc()).first()
    
    if not verification:
        return False
        
    return True

# 添加token验证装饰器
def token_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        token = request.headers.get('Authorization')
        if not token:
            return unauthorized('缺少token')
            
        user = User.query.filter_by(token=token).first()
        if not user or not user.check_token():
            return unauthorized('token无效或已过期')
            
        return f(*args, **kwargs)
    return decorated_function

@auth_bp.route('/api/auth/register', methods=['POST'])
def register():
    try:
        data = request.get_json()
        
        if not data or not all(k in data for k in ('username', 'password', 'phone', 'code')):
            return bad_request('请提供完整的注册信息（用户名、密码、手机号和验证码）')
        
        # 数据清理和验证
        username = data['username'].strip()
        password = data['password']
        phone = data['phone'].strip()
        code = data['code'].strip()
        
        if not username or len(username) < 3:
            return bad_request('用户名不能少于3个字符')
            
        if not password or len(password) < 6:
            return bad_request('密码不能少于6个字符')
        
        # 验证手机号格式
        if not is_valid_phone(phone):
            return bad_request('无效的手机号格式')
        
        # 验证验证码
        if not verify_code(phone, code):
            return bad_request('验证码无效或已过期')
        
        if User.query.filter_by(username=username).first():
            return bad_request('用户名已存在')
            
        if User.query.filter_by(phone=phone).first():
            return bad_request('手机号已被注册')
        
        # 创建新用户
        user = User(username=username, phone=phone)
        user.set_password(password)
        
        # 标记验证码为已使用
        VerificationCode.query.filter_by(
            phone=phone,
            code=code,
            is_used=False
        ).update({'is_used': True})
        
        db.session.add(user)
        db.session.commit()
        
        return jsonify({
            'code': 200,
            'message': '注册成功',
            'data': {
                'user_id': user.id,
                'username': user.username
            }
        }), 201
        
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(f'注册失败: {str(e)}')
        return bad_request('注册失败，请稍后重试')

@auth_bp.route('/api/auth/login', methods=['POST'])
def login():
    try:
        data = request.get_json()
        if not data:
            return bad_request('无效的请求数据')

        login_type = data.get('login_type')
        if not login_type:
            return bad_request('请指定登录类型')

        if login_type == 'phone':
            # 手机号验证码登录
            phone = str(data.get('phone', '')).strip()
            code = str(data.get('code', '')).strip()
            
            if not phone or not code:
                return bad_request('请提供手机号和验证码')
            
            if not is_valid_phone(phone):
                return bad_request('无效的手机号格式')
            
            # 验证验证码
            if not verify_code(phone, code):
                return bad_request('验证码无效或已过期')

            # 标记验证码为已使用
            VerificationCode.query.filter_by(
                phone=phone,
                code=code,
                is_used=False
            ).update({'is_used': True})
            
            user = User.query.filter_by(phone=phone).first()
            if not user:
                # 创建新用户
                user = User(
                    phone=phone,
                    password='',  # 验证码登录不需要密码
                    name=f'用户{phone[-4:]}',  # 默认用手机号后4位作为用户名
                    gender=0,  # 默认性别未知
                    description='',  # 默认空简介
                    avatar=''  # 默认空头像
                )
                db.session.add(user)

        elif login_type == 'wechat':
            # 微信一键登录
            openid = data.get('openid')
            if not openid:
                return bad_request('缺少openid参数')

            user = User.query.filter_by(openid=openid).first()
            if not user:
                return bad_request('请先使用手机号登录并绑定微信')

        else:
            return bad_request('不支持的登录类型')

        # 生成新token
        token = user.generate_token()
        db.session.commit()
        
        return jsonify({
            'code': 200,
            'message': '登录成功',
            'data': {
                'user_info': user.to_dict(),
                'token': token
            }
        })

    except Exception as e:
        db.session.rollback()
        current_app.logger.error(f'登录失败: {str(e)}')
        return bad_request('登录失败，请稍后重试')

@auth_bp.route('/api/auth/logout', methods=['POST'])
@token_required
def logout():
    """退出登录"""
    try:
        # 从请求头获取token
        token = request.headers.get('Authorization')
        if not token:
            return unauthorized('缺少token')
            
        # 根据token获取用户
        user = User.query.filter_by(token=token).first()
        if not user:
            return unauthorized('无效的token')
            
        # 清除用户token
        user.token = None
        user.token_expired = None
        db.session.commit()
        
        return jsonify({
            'code': 200,
            'message': '退出成功'
        })
        
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(f'退出登录失败: {str(e)}')
        return bad_request('退出失败，请稍后重试')

@auth_bp.route('/api/auth/bind-wechat', methods=['POST'])
@login_required
def bind_wechat():
    """绑定微信openid"""
    try:
        data = request.get_json()
        if not data or not data.get('openid'):
            return bad_request('请提供openid')
        
        openid = data['openid']
        
        # 检查openid是否已被绑定
        if User.query.filter_by(openid=openid).first():
            return bad_request('该微信账号已被绑定')
        
        current_user.openid = openid
        current_user.avatar = data.get('avatar', current_user.avatar)
        db.session.commit()
        
        return jsonify({
            'code': 200,
            'message': '绑定成功',
            'data': current_user.to_dict()
        })
        
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(f'绑定微信失败: {str(e)}')
        return bad_request('绑定失败，请稍后重试')

@auth_bp.route('/api/user/info', methods=['POST'])
@token_required
def get_user_info():
    """获取当前登录用户信息"""
    try:
        token = request.headers.get('Authorization')
        user = User.query.filter_by(token=token).first()
        return jsonify({
            'code': 200,
            'message': '获取成功',
            'data': user.to_dict()
        })
    except Exception as e:
        current_app.logger.error(f'获取用户信息失败: {str(e)}')
        return bad_request('获取用户信息失败')

@auth_bp.route('/api/user/info/detail', methods=['POST'])
@token_required
def get_user_info_by_id():
    """获取用户信息"""
    try:
        # 从请求头获取token
        token = request.headers.get('Authorization')
        if not token:
            return unauthorized('缺少token')
            
        # 根据token获取用户信息
        user = User.query.filter_by(token=token).first()
        if not user:
            return unauthorized('无效的token')
            
        return jsonify({
            'code': 200,
            'message': '获取成功',
            'data': user.to_dict()
        })
    except Exception as e:
        current_app.logger.error(f'获取用户信息失败: {str(e)}')
        return bad_request('获取用户信息失败')

@auth_bp.route('/api/user/update', methods=['POST'])
@token_required
def update_user_info():
    """修改用户信息"""
    try:
        data = request.get_json()
        if not data:
            return bad_request('请提供要修改的信息')

        # 从请求头获取token
        token = request.headers.get('Authorization')
        if not token:
            return unauthorized('缺少token')
            
        # 根据token获取用户
        user = User.query.filter_by(token=token).first()
        if not user:
            return unauthorized('无效的token')

        # 允许修改的字段
        allowed_fields = ['name', 'gender', 'description', 'avatar']
        updates = {}

        # 验证并收集要更新的字段
        for field in allowed_fields:
            if field in data:
                # 特殊字段的验证
                if field == 'name':
                    name = data['name'].strip()
                    if not name or len(name) > 50:
                        return bad_request('用户名长度不符合要求')
                    updates[field] = name
                elif field == 'gender':
                    gender = data['gender']
                    if gender not in [0, 1, 2]:
                        return bad_request('无效的性别值')
                    updates[field] = gender
                elif field == 'description':
                    description = data['description'].strip()
                    if len(description) > 500:
                        return bad_request('个人简介过长')
                    updates[field] = description
                elif field == 'avatar':
                    avatar = data['avatar'].strip()
                    if len(avatar) > 255:
                        return bad_request('头像URL过长')
                    updates[field] = avatar

        if not updates:
            return bad_request('没有提供任何要修改的信息')

        # 更新用户信息
        for field, value in updates.items():
            setattr(user, field, value)

        db.session.commit()

        return jsonify({
            'code': 200,
            'message': '修改成功',
            'data': user.to_dict()
        })

    except Exception as e:
        db.session.rollback()
        current_app.logger.error(f'修改用户信息失败: {str(e)}')
        return bad_request('修改用户信息失败，请稍后重试')

@auth_bp.route('/api/auth/delete-account', methods=['POST'])
@token_required
def delete_account():
    """注销用户账号"""
    try:
        # 从请求头获取token
        token = request.headers.get('Authorization')
        if not token:
            return unauthorized('缺少token')
            
        # 根据token获取用户
        user = User.query.filter_by(token=token).first()
        if not user:
            return unauthorized('无效的token')
            
        try:
            # 删除用户
            db.session.delete(user)
            db.session.commit()
            
            return jsonify({
                'code': 200,
                'message': '账号注销成功'
            })
            
        except Exception as e:
            db.session.rollback()
            current_app.logger.error(f'删除用户失败: {str(e)}')
            return bad_request('注销失败，请稍后重试')
            
    except Exception as e:
        current_app.logger.error(f'注销账号失败: {str(e)}')
        return bad_request('注销失败，请稍后重试') 